package testapp.client;

import java.util.ArrayList;
import java.util.List;

import testapp.client.animation.AnimationCallbackPart;
import testapp.client.animation.CompositeAnimationFrame;
import testapp.client.handler.FinishEditHandler;
import testapp.client.handler.StartEditHandler;
import testapp.client.handler.SwipeNoteHandler;
import testapp.client.util.AppContext;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.event.dom.client.TouchEndHandler;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchMoveHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class Note extends Composite {
    interface MyUiBinder extends UiBinder<Widget, Note> {}

    private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

    @UiField FlowPanel delegate;

    @UiField Label label;

    @UiField TextBox textBox;

    private long lastTouchTime;

    private List<FinishEditHandler> finishEditHandlers = new ArrayList<FinishEditHandler>();

    private List<StartEditHandler> startEditHandlers = new ArrayList<StartEditHandler>();

    private List<SwipeNoteHandler> swipeNoteHandlers = new ArrayList<SwipeNoteHandler>();

    private int swipeStartX;

    private int scrollX;

    private boolean isNoteEdit;

    private AnimationCallbackPart animationCallbackPart;

    public Note(String text) {
        initWidget(uiBinder.createAndBindUi(this));

        label.setText(text);
        textBox.setText(text);

        animationCallbackPart = new AnimationCallbackPart() {
            @Override
            public void execute() {
                delegate.getElement().getStyle().setProperty("webkitTransform", "translate3d(" + scrollX + "px, 0px, 0px)");
            }
        };

        CompositeAnimationFrame.getInstance().addAnimationCallbackPart(animationCallbackPart);

        label.addTouchStartHandler(new TouchStartHandler() {
            @Override
            public void onTouchStart(TouchStartEvent event) {
                if (System.currentTimeMillis() - lastTouchTime < 500) {
                    isNoteEdit = true;

                    label.getElement().getStyle().setDisplay(Style.Display.NONE);
                    textBox.getElement().getStyle().setDisplay(Style.Display.BLOCK);

                    delegate.getElement().getStyle().setBackgroundColor("rgb(255, 225, 161)");
                    textBox.getElement().getStyle().setBackgroundColor("rgb(255, 225, 161)");

                    textBox.setFocus(true);

                    for (StartEditHandler startEditHandler : startEditHandlers) {
                        startEditHandler.onStartEdit(Note.this);
                    }
                }

                lastTouchTime = System.currentTimeMillis();
            }
        });

        delegate.addDomHandler(new TouchStartHandler() {
            @Override
            public void onTouchStart(TouchStartEvent event) {
                if (!isNoteEdit) {
                    swipeStartX = event.getTouches().get(0).getPageX();

                    delegate.getElement().getStyle().setProperty("webkitTransition", "-webkit-transform 0s linear");
                }
            }
        }, TouchStartEvent.getType());

        delegate.addDomHandler(new TouchMoveHandler() {
            @Override
            public void onTouchMove(TouchMoveEvent event) {
                if (!isNoteEdit) {
                    int deltaX = event.getTouches().get(0).getPageX() - swipeStartX;

                    int unsensitiveZoneInPc = 20 * Window.getClientWidth() / 100;

                    if (AppContext.getInstance().getActivePanel() == 0) {
                        deltaX -= unsensitiveZoneInPc;
                    } else {
                        deltaX += unsensitiveZoneInPc;
                    }

                    if ((AppContext.getInstance().getActivePanel() == 0 && deltaX < 0) || (AppContext.getInstance().getActivePanel() == 1 && deltaX > 0))  {
                        deltaX = 0;
                    }

                    scrollX = deltaX;

                    event.preventDefault();
                }
            }
        }, TouchMoveEvent.getType());

        delegate.addDomHandler(new TouchEndHandler() {
            @Override
            public void onTouchEnd(TouchEndEvent event) {
                if (!isNoteEdit) {
                    int elementOffset = delegate.getAbsoluteLeft() * 100 / Window.getClientWidth();

                    int deltaX;

                    if (AppContext.getInstance().getActivePanel() == 0) {
                        if (elementOffset >= 30) {
                            deltaX = Window.getClientWidth();
                        } else {
                            deltaX = 0;
                        }
                    } else {
                        if (elementOffset <= -30) {
                            deltaX = -Window.getClientWidth();
                        } else {
                            deltaX = 0;
                        }
                    }

                    delegate.getElement().getStyle().setProperty("webkitTransition", "-webkit-transform 0.2s ease-out");

                    scrollX = deltaX;

                    if (deltaX != 0) {
                        Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
                            @Override
                            public boolean execute() {
                                CompositeAnimationFrame.getInstance().removeAnimationCallbackPart(animationCallbackPart);

                                for (SwipeNoteHandler swipeNoteHandler : swipeNoteHandlers) {
                                    swipeNoteHandler.onSwipe(Note.this);
                                }

                                return false;
                            }
                        }, 300);
                    }
                }
            }
        }, TouchEndEvent.getType());

        textBox.addKeyDownHandler(new KeyDownHandler() {
            @Override
            public void onKeyDown(KeyDownEvent event) {
                if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
                    finishEdit();
                }
            }
        });

        textBox.addBlurHandler(new BlurHandler() {
            @Override
            public void onBlur(BlurEvent event) {
                finishEdit();
            }
        });
    }

    private void finishEdit() {
        isNoteEdit = false;

        label.getElement().getStyle().setDisplay(Style.Display.BLOCK);
        textBox.getElement().getStyle().setDisplay(Style.Display.NONE);

        delegate.getElement().getStyle().setBackgroundColor("rgb(255, 255, 255)");
        textBox.getElement().getStyle().setBackgroundColor("rgb(255, 255, 255)");

        label.setText(textBox.getText());

        if (AppContext.getInstance().getPhoneGap().isPhoneGapDevice()) {
            AppContext.getInstance().hideKeyBoard();
        }

        for (FinishEditHandler finishEditHandler : finishEditHandlers) {
            finishEditHandler.onFinishEdit(this);
        }
    }

    public void addFinishEditHandler(FinishEditHandler finishEditHandler) {
        finishEditHandlers.add(finishEditHandler);
    }

    public void addStartEditHandler(StartEditHandler startEditHandler) {
        startEditHandlers.add(startEditHandler);
    }

    public void addSwipeNoteHandler(SwipeNoteHandler swipeNoteHandler) {
        swipeNoteHandlers.add(swipeNoteHandler);
    }

    public Label getLabel() {
        return label;
    }
}
